﻿using System;
using System.Collections.Generic;
using sdd.subsystems.display;
using sdd.subsystems.ui;

namespace sdd.subsystems.ui.screens
{
    public class ScrMenu : IScreen
    {

        #region Constructor / Destructor
        public ScrMenu(string screenName, string menuTitle, MenuItem rootMenuItem)
        {
            _menuDisplayTitle = menuTitle;
            _screenName = screenName;
            _rootMenu = rootMenuItem;
        }

        ~ScrMenu()
        {

        }

        #endregion

        #region IScreen Implementation
        private int _SelectorPosition = 0;
        private int _SubItemsStartPos = 0;
        private MenuItem _CurrentCategoryMenu;
        private int _CurrentCategoryMenuId;

        private string _menuDisplayTitle = "Menu";
        private string _screenName = "ScrMenu";
        private MenuItem _rootMenu = new MenuItem("root", "Root Menu");



        public event EventHandler<AppKeyPressEventArgs> AppKeyPress;

        public string ScreenName { get { return _screenName; } }
        
        public int SelectorPosition
        {
            get { return _SelectorPosition; }
            set
            {
                _SelectorPosition = value;
                DrawSelector();
            }
        }
        
        public IDisplay Display { get; set; }
        public ScreenManager Manager { get; set; }
        
        public void Initialize()
        {
            lock (Display.SyncLock) { Display.InitializeTextWindow(ScreenManager.WINDOW_MENU_SUBITEMS, 8, 26, 185, 64, ScreenManager.FONT_PROP_SMALL, 1, 1, 0);  }
            
            if (_rootMenu.SubItems.Count > 0)
            {
                // first sub item of root menu is our first top-level menu
                _CurrentCategoryMenu = _rootMenu.SubItems[0];
            }                        
            _CurrentCategoryMenuId = 1;
        }

        public void Show()
        {
            if (_CurrentCategoryMenu == null)
            {
                _CurrentCategoryMenu = _rootMenu.SubItems[0];
                _CurrentCategoryMenuId = 1;
            }
            DrawHeader();
            DrawCategoryMenu();
            DrawNavigator();
            DrawSubMenu(_CurrentCategoryMenu);
            DrawSelector();
        }

        public void Hide()
        {
            //throw new NotImplementedException();
        }

        public void ProcessKeyPadEvent(KeypadEventArgs keyPadEventArgs)
        {
            var SelectedItem = GetSelectedSubMenuItem();
            var SelectedMenu = GetSelectedTopMenuItem();

            switch (keyPadEventArgs.Key)
            {
                case KeypadKeys.Down:
                    ProcessCmdDown();
                    break;

                case KeypadKeys.Up:
                    ProcessCmdUp();
                    break;

                case KeypadKeys.Center:
                    ProcessCmdCenter(SelectedItem);
                    break;

                case KeypadKeys.Left:
                    ProcessCmdLeft(SelectedItem);
                    break;

                case KeypadKeys.Right:
                    ProcessCmdRight(SelectedItem);
                    break;
                
                case KeypadKeys.App:
                    AppKeyPressEventArgs e = new AppKeyPressEventArgs();
                    if (AppKeyPress != null) { AppKeyPress(this, e); }
                    if (e.Handled)
                    {
                        // custom handler, see if we should give buzzer feedback
                        if (e.KeypressFeedbackBuzz) { Manager.Buzz(); }
                    }
                    else
                    {
                        // default handler (go back to previous screen)
                        Manager.Buzz();
                        Manager.Show(Manager.PreviousScreen);
                    }
                    break;
            }
        }
        #endregion

        #region Private Methods
        private void ProcessCmdCenter(MenuItem SelectedItem)
        {
            if (SelectedItem is LinkMenuItem)
            {
                Manager.Buzz();
                LinkMenuItem lnk = (LinkMenuItem)(SelectedItem);
                Manager.Show(lnk.LinkedScreen);
            }
            else if (SelectedItem is IToggleableMenutItem)
            {
                Manager.Buzz();
                IToggleableMenutItem tog = (IToggleableMenutItem)(SelectedItem);
                tog.Toggle();
                DrawSubMenu(_CurrentCategoryMenu);
            }
            else if (SelectedItem is IClickableMenuItem)
            {
                Manager.Buzz();
                IClickableMenuItem clk = (IClickableMenuItem)(SelectedItem);
                clk.Click();
            }
        }

        private void ProcessCmdLeft(MenuItem SelectedItem)
        {
            if (SelectedItem == null)
            {
                if (_CurrentCategoryMenuId > 1)
                {
                    _CurrentCategoryMenuId--;
                    _CurrentCategoryMenu = GetSelectedTopMenuItem();
                    DrawCategoryMenu();
                    DrawNavigator();
                    DrawSubMenu(_CurrentCategoryMenu);
                    Manager.Buzz();
                }
            }
            if (SelectedItem is IToggleableMenutItem)
            {
                Manager.Buzz();
                IToggleableMenutItem togl = (IToggleableMenutItem)SelectedItem;
                togl.Toggle();
                DrawSubMenu(_CurrentCategoryMenu);
            }
            if (SelectedItem is IBrowseableMenuItem)
            {
                Manager.Buzz();
                IBrowseableMenuItem brws = (IBrowseableMenuItem)SelectedItem;
                brws.Previous();
                DrawSubMenu(_CurrentCategoryMenu);
            }
            if (SelectedItem is ICountableMenuItem)
            {
                ICountableMenuItem cnt = (ICountableMenuItem)SelectedItem;
                try
                {
                    cnt.Decrease();
                    Manager.Buzz();
                    DrawSubMenu(_CurrentCategoryMenu);
                }
                catch (ArgumentOutOfRangeException)
                {
                    // couldn't decrease, don't buzz
                }   
            }
        }

        private void ProcessCmdRight(MenuItem SelectedItem)
        {
            if (SelectedItem == null)
            {
                //if (_CurrentCategoryMenuId < Manager.Menus.Count)
                if (_CurrentCategoryMenuId < _rootMenu.SubItems.Count)
                {
                    Manager.Buzz();
                    _CurrentCategoryMenuId++;
                    _CurrentCategoryMenu = GetSelectedTopMenuItem();
                    DrawCategoryMenu();
                    DrawNavigator();
                    DrawSubMenu(_CurrentCategoryMenu);
                }
            }
            if (SelectedItem is IToggleableMenutItem)
            {
                Manager.Buzz();
                IToggleableMenutItem togl = (IToggleableMenutItem)SelectedItem;
                togl.Toggle();
                DrawSubMenu(_CurrentCategoryMenu);
            }
            if (SelectedItem is IBrowseableMenuItem)
            {
                Manager.Buzz();
                IBrowseableMenuItem brws = (IBrowseableMenuItem)SelectedItem;
                brws.Next();
                DrawSubMenu(_CurrentCategoryMenu);
            }
            if (SelectedItem is ICountableMenuItem)
            {
                ICountableMenuItem cnt = (ICountableMenuItem)SelectedItem;
                try
                {
                    cnt.Increase();
                    Manager.Buzz();
                    DrawSubMenu(_CurrentCategoryMenu);
                }
                catch (ArgumentOutOfRangeException)
                {
                    // could not increase, don't buzz
                }                
            }
        }

        private void ProcessCmdUp()
        {
            if (SelectorPosition == 1)
            {
               if (_SubItemsStartPos > 0)
               {
                   Manager.Buzz();
                   _SubItemsStartPos--;
                   DrawSubMenu(_CurrentCategoryMenu, _SubItemsStartPos);
               }
               else
               {
                   // move to top level selection (selector position 0)
                   SelectorPosition--;
                   Manager.Buzz();
               }
            }
            else if (SelectorPosition > 1)
            {
                SelectorPosition--;
                Manager.Buzz();
            }
            else
            {
                if (_SubItemsStartPos > 0)
                {
                    Manager.Buzz();
                    _SubItemsStartPos--;
                    DrawSubMenu(_CurrentCategoryMenu, _SubItemsStartPos);
                }
            }
        }

        private void ProcessCmdDown()
        {
            if (_CurrentCategoryMenu != null)
            {
                if (SelectorPosition < 4 & SelectorPosition < _CurrentCategoryMenu.SubItems.Count)
                {
                    Manager.Buzz();
                    SelectorPosition++;
                }
                else
                {
                    if (_CurrentCategoryMenu.SubItems.Count > 4)
                    {
                        if (_SubItemsStartPos + 4 < _CurrentCategoryMenu.SubItems.Count)
                        {
                            Manager.Buzz();
                            _SubItemsStartPos++;
                            DrawSubMenu(_CurrentCategoryMenu, _SubItemsStartPos);
                        }
                    }
                }
            }
        }

        private MenuItem GetSelectedTopMenuItem()
        {
            int i = 1;
            //foreach (MenuItem item in Manager.Menus)
            foreach (MenuItem item in _rootMenu.SubItems)
            {
                if (_CurrentCategoryMenuId == i)
                {
                    return item;
                    
                }
                i++;
            }
            return null;
        }

        private int GetLastMenuItemId()
        {
            return _rootMenu.SubItems.Count;
        }

        private MenuItem GetSelectedSubMenuItem()
        {
            if (_CurrentCategoryMenu != null)
            {
                int i = -1;
                MenuItem[] SubItems = new MenuItem[_CurrentCategoryMenu.SubItems.Count];
                foreach (MenuItem item in _CurrentCategoryMenu.SubItems)
                {
                    i++;
                    SubItems[i] = item;
                }

                int selectedEntryNo = _SubItemsStartPos + SelectorPosition - 1;
                if (selectedEntryNo >= 0)
                {
                    return SubItems[selectedEntryNo];
                }
                else
                {
                    return null;
                }
            }
            else
            {
                return null;
            }
        }

        private void DrawHeader()
        {
            lock (Display.SyncLock)
            {
                Display.SetCursorCoordinate(0, 0);
                Display.SetCurrentFont(ScreenManager.FONT_PROP_LARGE);
                Display.WriteText(_menuDisplayTitle);
                Display.DrawLine(0, 14, 192, 14);
            }
        }

        private void DrawCategoryMenu()
        {
            lock (Display.SyncLock)
            {
                Display.DrawFilledRectangle(0, 8, 18, 174, 26);
                Display.SetCursorCoordinate(8, 18);
                Display.SetCurrentFont(ScreenManager.FONT_PROP_SMALL);
                if (_CurrentCategoryMenu != null)
                {
                    Display.WriteText(_CurrentCategoryMenu.Caption);
                }
            }
        }

        private void DrawNavigator()
        {
            lock (Display.SyncLock)
            {
                Display.DrawFilledRectangle(0, 175, 18, 192, 26);
                Display.SetCursorCoordinate(175, 18);
                Display.SetCurrentFont(ScreenManager.FONT_PROP_SMALL);

                if (_CurrentCategoryMenu != null)
                {
                    if (GetLastMenuItemId() > 1)
                    {
                        if (_CurrentCategoryMenuId == 1)
                        {
                            Display.SetCursorCoordinate(185, 18);
                            Display.WriteText(">>");
                        }
                        else if (_CurrentCategoryMenuId == GetLastMenuItemId())
                        {
                            Display.SetCursorCoordinate(185, 18);
                            Display.WriteText("<<");
                        }
                        else
                        {
                            Display.WriteText("<< >>");
                        }
                    }
                }
            }
        }

        private void DrawSubMenu(MenuItem parentMenu, int startItemNo = 0)
        {
            if (parentMenu != null)
            {
                lock (Display.SyncLock)
                {
                    Display.ClearTextWindow(ScreenManager.WINDOW_MENU_SUBITEMS);
                    Display.SetTextWindow(ScreenManager.WINDOW_MENU_SUBITEMS);
                    Display.DrawLine(8, 27, 192, 27);
                    int i = 0;
                    i = 0;
                    for (int j = startItemNo; (j < parentMenu.SubItems.Count & j < startItemNo + 4); j++)
                    {
                        // print item name
                        Display.SetCursorCoordinate(8, (byte)(31 + (i * 8)));
                        Display.WriteText(parentMenu.SubItems[j].Caption);
                        // print item value
                        Display.SetCursorCoordinate(100, (byte)(31 + (i * 8)));
                        var menuItem = parentMenu.SubItems[j];
                        if (menuItem is IPrintableValueMenuItem)
                        {
                            IPrintableValueMenuItem prnt = (IPrintableValueMenuItem)menuItem;
                            Display.WriteText(prnt.Print());
                        }
                        i++;
                    }
                    Display.SetTextWindow(ScreenManager.WINDOW_DEFAULT);
                }
            }
        }

        private void DrawSelector()
        {
            lock (Display.SyncLock)
            {
                // clear selector area
                Display.DrawFilledRectangle(0, 0, 15, 7, 64);
                // draw new selector
                Display.SetCurrentFont(ScreenManager.FONT_MONO_AUDIOSYMBOLS);
                switch (SelectorPosition)
                {
                    case 0:
                        // top level menu selection
                        Display.SetCursorCoordinate(0, 18);
                        Display.WriteText("A");
                        break;
                    default:
                        // subitem menu selection
                        Display.SetCursorCoordinate(0, (byte)(31 + ((SelectorPosition - 1) * 8)));
                        Display.WriteText("A");
                        break;
                }
            }
        }

    #endregion


        public apps.IApplication Application { set; get; }
    }

    public class AppKeyPressEventArgs : EventArgs
    {
        public AppKeyPressEventArgs(bool feedbackBuzz = false, bool handled = false)
        {
            KeypressFeedbackBuzz = feedbackBuzz;
            Handled = handled;
        }
        public bool KeypressFeedbackBuzz { set; get; }
        public bool Handled { set; get; }
    }
}
